package com.ruoyi.spot.realtime.transactionrecord.controller;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.spot.constants.SpotMonitorConstants;
import com.ruoyi.util.LarkDangerRobotUtils;
import com.ruoyi.util.LarkRecoverRobotUtils;
import com.ruoyi.util.WebSocketUtilsReq;
import com.ruoyi.spot.realtime.transactionrecord.domain.VO.SpotTransactionRecordRealtimeDataVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.spot.realtime.transactionrecord.domain.SpotTransactionRecordRealtimeData;
import com.ruoyi.spot.realtime.transactionrecord.service.ISpotTransactionRecordRealtimeDataService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 实时获取成交记录Controller
 *
 * @author saumell
 * @date 2024-08-07
 */
@RestController
@RequestMapping("/spotrealtimetransaction/spotrealtimetransactionbak")
public class SpotTransactionRecordRealtimeDataController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(SpotTransactionRecordRealtimeDataController.class);

    @Autowired
    private ISpotTransactionRecordRealtimeDataService spotTransactionRecordRealtimeDataService;

    @Value("${my.lark.dangerlark}")
    private String dangerlark;

    @Value("${my.lark.recoverlark}")
    private String recoverlark;

    /**
     * 查询实时获取成交记录列表
     */
    @PreAuthorize("@ss.hasPermi('spotrealtimetransaction:spotrealtimetransactionbak:list')")
    @GetMapping("/list")
    public TableDataInfo list(SpotTransactionRecordRealtimeDataVO spotTransactionRecordRealtimeData) {
        startPage();
        List<SpotTransactionRecordRealtimeDataVO> list = spotTransactionRecordRealtimeDataService.selectSpotTransactionRecordRealtimeDataList(spotTransactionRecordRealtimeData);
        return getDataTable(list);
    }

    /**
     * 导出实时获取成交记录列表
     */
    @PreAuthorize("@ss.hasPermi('spotrealtimetransaction:spotrealtimetransactionbak:export')")
    @Log(title = "实时获取成交记录", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, SpotTransactionRecordRealtimeDataVO spotTransactionRecordRealtimeData) {
        List<SpotTransactionRecordRealtimeDataVO> list = spotTransactionRecordRealtimeDataService.selectSpotTransactionRecordRealtimeDataList(spotTransactionRecordRealtimeData);
        ExcelUtil<SpotTransactionRecordRealtimeDataVO> util = new ExcelUtil<SpotTransactionRecordRealtimeDataVO>(SpotTransactionRecordRealtimeDataVO.class);
        util.exportExcel(response, list, "实时获取成交记录数据");
    }

    /**
     * 获取实时获取成交记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('spotrealtimetransaction:spotrealtimetransactionbak:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Integer id) {
        return success(spotTransactionRecordRealtimeDataService.selectSpotTransactionRecordRealtimeDataById(id));
    }


    /**
     * 判断返回值状态
     *
     * @param websocketResponse
     * @return
     */
    public static String determineReturnValue(String websocketResponse) {
        try {
            // 解析 JSON 字符串
            JSONObject jsonObject = JSONObject.parseObject(websocketResponse);

            // 校验 event_rep
            String eventRep = jsonObject.getString("event_rep");
            if (!"rep".equals(eventRep)) {
                return "false,【event_rep】字段不为 'rep'";
            }

            // 校验 channel
            String channel = jsonObject.getString("channel");
            if (channel == null || channel.isEmpty()) {
                return "false,【channel】数据为空";
            }

            // 校验 ts
            long ts = jsonObject.getLongValue("ts");
            if (ts <= 0) {
                return "false,【ts】时间戳无效";
            }

            // 校验 data 数组
            JSONArray dataArray = jsonObject.getJSONArray("data");
            if (dataArray == null || dataArray.isEmpty()) {
                return "false,【data】数据为空";
            }

            // 校验每条 历史交易数据
            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject dataObject = dataArray.getJSONObject(i);

                double amount = dataObject.getDoubleValue("amount");
                long dataTs = dataObject.getLongValue("ts");
                double vol = dataObject.getDoubleValue("vol");
                double price = dataObject.getDoubleValue("price");
                String side = dataObject.getString("side");

                // 校验交易数据字段
                if (amount < 0 || vol < 0 || price < 0 || dataTs <= 0 || side == null || side.isEmpty()) {
                    return "false,【data】数据字段无效";
                }
            }

            // 如果所有校验都通过，则返回 "true"
            return "true";
        } catch (Exception e) {
            return "false,JSON解析错误: " + e.getMessage();
        }
    }

    /**
     * 通过Websocket实时订阅，监控现货获取成交记录返回值内容
     */

    public void spotTransactionRecordMonitor() {
        List<SpotTransactionRecordRealtimeDataVO> spotTransactionRecordList = spotTransactionRecordRealtimeDataService.selectSpotAllData();
        //新建放置需要报警、故障修复交易对的id
        List<Integer> dangerProductionInspections = new ArrayList<Integer>();
        List<Integer> recoverProductionInspections = new ArrayList<Integer>();
        for (SpotTransactionRecordRealtimeDataVO spotTransactionRecordRealtimeDataVO : spotTransactionRecordList) {
            Integer id = spotTransactionRecordRealtimeDataVO.getId();
            String currencyPair = spotTransactionRecordRealtimeDataVO.getCurrencyPair();
            String callingState = spotTransactionRecordRealtimeDataVO.getCallingState();
            Date lastExecutionTime = spotTransactionRecordRealtimeDataVO.getLastExecutionTime();
            Integer successTimes = spotTransactionRecordRealtimeDataVO.getSuccessTimes();
            Integer failTimes = spotTransactionRecordRealtimeDataVO.getFailTimes();
            Integer dangerWarning = spotTransactionRecordRealtimeDataVO.getDangerWarning();
            Integer safeWarning = spotTransactionRecordRealtimeDataVO.getSafeWarning();
            String websocketResponse = null;
            WebSocketUtilsReq webSocketUtilsReq = null;
            try {
                String subParam = "{\"event\":\"req\",\"params\":{\"channel\":\"market_" + currencyPair + "_trade_ticker\",\"cb_id\":\"1\"}}";
                webSocketUtilsReq = new WebSocketUtilsReq(SpotMonitorConstants.SPOT_WEBSOCKET_TRANSACTION_RECORD_URL, subParam);
                websocketResponse = webSocketUtilsReq.getDecompressedMessage();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 确保在每次循环结束后关闭 WebSocket 连接
                if (webSocketUtilsReq != null) {
                    webSocketUtilsReq.closeConnection();
                }
            }
            // 处理返回的响应
            if (websocketResponse == null || websocketResponse.isEmpty()) {
                //                现货获取成交记录-未接收到数据
                if (Objects.isNull(callingState) || callingState.isEmpty()) {
                    //数据库中没有数据，说明是第一次订阅即失败
                    //将调用失败的id放入dangerProductionInspections中
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    successTimes = 0;
                    failTimes = 1;
                    Integer currencysId = spotTransactionRecordRealtimeDataService.queryCurryNumber(currencyPair);
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, currencysId, "off_line", lastExecutionTime, successTimes, failTimes, "Server未推送Kline数据", null, null, null);
                    spotTransactionRecordRealtimeDataService.insertSpotTransactionRecordRealtimeData(o1);
                    dangerProductionInspections.add(o1.getId());
                    log.info("[现货获取成交记录-1}：【" + currencyPair + "】首次调用即失败");
                } else if (callingState.equals("off_line")) {
                    //订阅一直失败
                    //将调用失败的id放入dangerProductionInspections中
                    if (dangerWarning == null || dangerWarning == 1) {
                        dangerProductionInspections.add(id);
                    }
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    failTimes = failTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, "Server未推送Kline数据", null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-2}：【" + currencyPair + "】订阅一直失败");
                } else if (callingState.equals("on_line")) {
                    //此种情况为第一次订阅失败
                    //将调用失败的id放入dangerProductionInspections中
                    dangerProductionInspections.add(id);
                    callingState = "off_line";
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    failTimes = failTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, "Server未推送Kline数据", null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-3}：【" + currencyPair + "】订阅首次失败");
                } else {
                    log.info("+++++++++++++++++++++++++++订阅失败未知情况+++++++++++++++++++++++++++++++");
                    log.info("[现货获取成交记录-4}：【" + currencyPair + "】未知情况");
                }
            } else if (websocketResponse != null && determineReturnValue(websocketResponse) != null && determineReturnValue(websocketResponse).startsWith("false")) {
                // 处理返回值包含 "false" 的情况
                if (Objects.isNull(callingState) || callingState.isEmpty()) {
                    //数据库中没有数据，说明是第一次订阅即失败
                    //将调用失败的id放入dangerProductionInspections中
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    successTimes = 0;
                    failTimes = 1;
                    Integer currencysId = spotTransactionRecordRealtimeDataService.queryCurryNumber(currencyPair);
                    String s = determineReturnValue(websocketResponse);
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, currencysId, "off_line", lastExecutionTime, successTimes, failTimes, determineReturnValue(websocketResponse).split(",")[1], null, null, null);
                    spotTransactionRecordRealtimeDataService.insertSpotTransactionRecordRealtimeData(o1);
                    dangerProductionInspections.add(o1.getId());
                    log.info("[现货获取成交记录-5}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else if (callingState.equals("off_line")) {
                    //订阅一直失败
                    //将调用失败的id放入dangerProductionInspections中
                    if (dangerWarning == null || dangerWarning == 1) {
                        dangerProductionInspections.add(id);
                    }
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    failTimes = failTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, determineReturnValue(websocketResponse).split(",")[1], null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-6}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else if (callingState.equals("on_line")) {
                    //此种情况为第一次订阅失败
                    //将调用失败的id放入dangerProductionInspections中
                    dangerProductionInspections.add(id);
                    callingState = "off_line";
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    failTimes = failTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, determineReturnValue(websocketResponse).split(",")[1], null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-7}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else {
                    log.info("+++++++++++++++++++++++++++订阅失败未知情况+++++++++++++++++++++++++++++++");
                    log.info("[现货获取成交记录-8}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                }
            } else if (websocketResponse != null && determineReturnValue(websocketResponse) != null && determineReturnValue(websocketResponse).equals("true")) {
//             订阅+格式校验均成功！
                if (Objects.isNull(callingState) || callingState.isEmpty()) {
//                    首次订阅
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    successTimes = 1;
                    failTimes = 0;
                    Integer currencysId = spotTransactionRecordRealtimeDataService.queryCurryNumber(currencyPair);
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, currencysId, "on_line", lastExecutionTime, successTimes, failTimes, null, null, null, null);
                    spotTransactionRecordRealtimeDataService.insertSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-9}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else if (callingState.equals("on_line")) {
//                    订阅一直成功
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    successTimes = successTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, null, null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-10}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else if (callingState.equals("off_line")) {
//                    订阅故障修复，复通
                    if (safeWarning == null || safeWarning == 1) {
                        recoverProductionInspections.add(id);
                    }
                    callingState = "on_line";
                    LocalDateTime currentDateTime = LocalDateTime.now();
                    lastExecutionTime = Timestamp.valueOf(currentDateTime);
                    successTimes = successTimes + 1;
                    SpotTransactionRecordRealtimeData o1 = new SpotTransactionRecordRealtimeData(id, null, callingState, lastExecutionTime, successTimes, failTimes, null, null, null, null);
                    spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o1);
                    log.info("[现货获取成交记录-11}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                } else {
                    log.info("+++++++++++++++++++++++++++订阅成功未知情况+++++++++++++++++++++++++++++++");
                    log.info("[现货获取成交记录-12}：【" + currencyPair + "】" + determineReturnValue(websocketResponse));
                }
            }
        }
        List<SpotTransactionRecordRealtimeDataVO> spotTransactionCurrencysList_new = spotTransactionRecordRealtimeDataService.selectSpotAllData();
        //        dangerProductionInspections :断开交易对对应id
        //        recoverProductionInspections  ：复通交易对对应id
        //        需要发送危险报警对象
        List<SpotTransactionRecordRealtimeDataVO> allProductionInspections2 = new ArrayList<>();
        //        需要发送复通信息对象
        List<SpotTransactionRecordRealtimeDataVO> allProductionInspections3 = new ArrayList<>();
        for (int i = 0; i < spotTransactionCurrencysList_new.size(); i++) {
            Integer id = spotTransactionCurrencysList_new.get(i).getId();
            if (dangerProductionInspections.contains(id)) {
                allProductionInspections2.add(spotTransactionCurrencysList_new.get(i));
            } else if (recoverProductionInspections.contains(id)) {
                allProductionInspections3.add(spotTransactionCurrencysList_new.get(i));
            }
        }

        if (!allProductionInspections2.isEmpty()) {
            if (allProductionInspections2.size() == 1) {
                // 如果只有一条数据
                String name = allProductionInspections2.get(0).getCurrencyPair();
                Date time = allProductionInspections2.get(0).getLastExecutionTime();
                String reason = allProductionInspections2.get(0).getLastFailureReason();
                String formattedDate = "";
                if (time != null) {
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    formattedDate = formatter.format(time);
                }
                // 拼接调用失败报警信息...
                String DangerLarkNotice = "【现货-获取成交记录-WebSocket】下方为历史K线故障的交易对名称及调用时间，请您关注！\n";
                DangerLarkNotice += "交易对名称： " + name + "   " + "故障时间： " + formattedDate + "    故障原因： " + reason + "   " + "\n";
                String dangernotice = LarkDangerRobotUtils.notice(DangerLarkNotice, dangerlark);
                // 更新数据库状态
                Integer id = allProductionInspections2.get(0).getId();
                String statusMessage = dangernotice.equals("lark_success") ? "Lark发送故障X信息情况成功！" : "Lark发送故障X信息情况失败！";
                SpotTransactionRecordRealtimeData o2 = new SpotTransactionRecordRealtimeData(id, null, null, null, null, null, null, dangernotice.equals("lark_success") ? 0 : 1, null, statusMessage);
                spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o2);
//                }
            } else {
                // 如果有多条数据，正常调用notice
                String DangerLarkNotice = "【现货-获取成交记录-WebSocket】下方为历史K线故障的交易对名称及调用时间，请您关注！\n";
                boolean needNotice = false; // 是否需要发送通知
                for (int i = 0; i < allProductionInspections2.size(); i++) {
                    String name = allProductionInspections2.get(i).getCurrencyPair();
                    Date time = allProductionInspections2.get(i).getLastExecutionTime();
                    String reason = allProductionInspections2.get(i).getLastFailureReason();
                    String formattedDate = "";
                    if (time != null) {
                        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        formattedDate = formatter.format(time);
                    }
                    DangerLarkNotice += "交易对名称： " + name + "   " + "故障时间： " + formattedDate + "    故障原因： " + reason + "   " + "\n";
                }
//                if (needNotice) {
                String dangernotice = LarkDangerRobotUtils.notice(DangerLarkNotice, dangerlark);
                // 检查通知是否成功发送
                if (dangernotice.equals("lark_success")) {
                    // 更新数据库状态
                    for (int i = 0; i < allProductionInspections2.size(); i++) {
                        Integer id = allProductionInspections2.get(i).getId();
                        String statusMessage = "Lark发送故障X信息情况成功！";
                        SpotTransactionRecordRealtimeData o2 = new SpotTransactionRecordRealtimeData(id, null, null, null, null, null, null, 0, null, statusMessage);
                        spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o2);
                    }
                } else {
                    // 更新数据库状态
                    for (int i = 0; i < allProductionInspections2.size(); i++) {
                        Integer id = allProductionInspections2.get(i).getId();
                        String statusMessage = "Lark发送故障X信息情况失败！";
                        SpotTransactionRecordRealtimeData o2 = new SpotTransactionRecordRealtimeData(id, null, null, null, null, null, null, 1, null, statusMessage);
                        spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o2);
                    }
                }
//                }
            }
        }

        if (allProductionInspections3.size() != 0) {
//            拼接重新调用成功对象
            String RecoverLarkNotice = "";
            RecoverLarkNotice += "【现货-获取成交记录-WebSocket】下方为K恢复的交易对名称及调用时间，请您关注！" + "\n";
            for (int i = 0; i < allProductionInspections3.size(); i++) {
                String name = allProductionInspections3.get(i).getCurrencyPair();
                Date time = allProductionInspections3.get(i).getLastExecutionTime();
                String formattedDate = "";
                if (time != null) {
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    formattedDate = formatter.format(time);
                }
                RecoverLarkNotice += "交易对名称： " + name + "   " + "恢复时间： " + formattedDate + "   " + "\n";
            }
            String recovernotice = LarkRecoverRobotUtils.notice(RecoverLarkNotice, recoverlark);
            for (int i = 0; i < allProductionInspections3.size(); i++) {
                //判断复通信息通知情况
                if (recovernotice.equals("lark_fail")) {
//                    通知失败
                    for (int j = 0; j < allProductionInspections3.size(); j++) {
                        Integer id = allProductionInspections3.get(j).getId();
                        SpotTransactionRecordRealtimeData o2 = new SpotTransactionRecordRealtimeData(id, null, null, null, null, null, null, null, 1, "Lark发送故障V信息情况失败！");
                        spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o2);
                    }
                } else {
//                    通知成功
                    for (int k = 0; k < allProductionInspections3.size(); k++) {
                        Integer id = allProductionInspections3.get(k).getId();
                        SpotTransactionRecordRealtimeData o2 = new SpotTransactionRecordRealtimeData(id, null, null, null, null, null, null, null, 0, "Lark发送故障V信息情况失败！");
                        spotTransactionRecordRealtimeDataService.updateSpotTransactionRecordRealtimeData(o2);
                    }
                }
            }
        }
        log.info("============【【现货-获取成交记录-WebSocket】执行完成============");


    }
}
